#pragma once
#include<iostream>
#include"TableInfo.h"
#include"MemRecordStore.h"
#include"IO.h"
#include"ResourcePool.h"
#include"Table.h"
using namespace std;

class RedoDataUtil{
public:
    
    static vector<pair<ResourceInfo, IndexRecord*>> getIndColDelInfoVec(const TableInfo* tableInfo, const vector<string>& colNameVec, const map<string, Basic*>& rowData,
                                                                        const int16_t& blockNo, const int32_t& ind)
    {
        vector<pair<ResourceInfo, IndexRecord*>> delInfo;
        for(size_t i = 0; i < colNameVec.size(); i++){
            const string& colName = colNameVec[i];
            Basic* data = rowData.at(colName);
            const ResourceInfo& resInfo = tableInfo->getProbIndResInfo(colName, data->getHashVal());
                                                //读数据已经拷贝了 这里不需要拷贝
            IndexRecord* indRec = new IndexRecord(data, new LocInfo(blockNo, ind), INDDEL);
            delInfo.push_back(make_pair(resInfo, indRec));
        }
        return delInfo;
    }



    static pair<ResourceInfo, uint64_t> recordToBitMapRecord(const Record* rec){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(rec->baseName, rec->tableName);
        const double& hashVal = rec->newData->getHashVal();
        const ResourceInfo& resInfo = tableInfo->getProbBitMapResInfo(rec->colName, hashVal);
        return make_pair(resInfo, hashVal);
    }

    

    static vector<pair<ResourceInfo, IndexRecord*>> addRecordToIndUpdateInfo(const Record* addRec){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(addRec->baseName, addRec->tableName);
        if(!tableInfo->isColWithInd(addRec->colName)){ return {}; }
        const Basic* addData = addRec->newData;
        const ResourceInfo& resInfo = tableInfo->getProbIndResInfo(addRec->colName, addData->getHashVal());
        IndexRecord* indRec = new IndexRecord(BasicUtil::getCopyBasicData(addData), new LocInfo(addRec->blockNo, addRec->opInd), INDADD);
        return {make_pair(resInfo, indRec)};
    }



    static vector<pair<ResourceInfo, IndexRecord*>> modRecordToIndUpdateInfo(const Record* modRec){
        TableInfo* tableInfo = TableInfoManager::getTableInfo(modRec->baseName, modRec->tableName);
        if(!tableInfo->isColWithInd(modRec->colName)){ return {}; }
        const Basic* oldData = modRec->oldData;
        const Basic* newData = modRec->newData;
        const ResourceInfo& oldDataResInfo = tableInfo->getProbIndResInfo(modRec->colName, oldData->getHashVal());
        const ResourceInfo& newDataResInfo = tableInfo->getProbIndResInfo(modRec->colName, newData->getHashVal());
        IndexRecord* indDelRec = new IndexRecord(BasicUtil::getCopyBasicData(oldData), new LocInfo(modRec->blockNo, modRec->opInd), INDDEL);
        IndexRecord* indAddRec = new IndexRecord(BasicUtil::getCopyBasicData(newData), new LocInfo(modRec->blockNo, modRec->opInd), INDADD);
        return {make_pair(oldDataResInfo, indDelRec), make_pair(newDataResInfo, indAddRec)};
    }



    static vector<pair<ResourceInfo, IndexRecord*>> delRecordToIndUpdateInfo(const Record* delRec){
        const string& baseName = delRec->baseName, tableName = delRec->tableName;
        TableInfo* tableInfo = TableInfoManager::getTableInfo(baseName, tableName);
        const vector<string>& colNameVec = tableInfo->getColNameVec(true);  //获取带索引的列的列名

        const map<string, Basic*>& rowData = TableOperator::currentReadRowData(baseName, tableName, colNameVec, LocInfo(delRec->blockNo, delRec->opInd), READ, nullptr);

        return getIndColDelInfoVec(tableInfo, colNameVec, rowData, delRec->blockNo, delRec->opInd);
    }
    


    static void addUpdateInfoToRecordStore(unordered_map<ResourceInfo, vector<IndexRecord*>, ResInfoHash>& indRecordStore,
                                           const vector<pair<ResourceInfo, IndexRecord*>>& upDateInfo)
    {
        for(const auto& it : upDateInfo){
            indRecordStore[it.first].push_back(it.second);
        }
    }



    static void addToBitMapRecordStore(unordered_map<ResourceInfo, vector<uint64_t>, ResInfoHash>& bitMapRecordStore, const vector<Record*>& unIncreWriteRecords){
        for(const Record* rec : unIncreWriteRecords){
            if(rec->opType == DEL){         //BitMap只做新增操作 修改的新值也算算新增
                continue;                   //删除不做修改
            }
            const pair<ResourceInfo, uint64_t>& bitMapRecord = recordToBitMapRecord(rec);
            bitMapRecordStore[bitMapRecord.first].push_back(bitMapRecord.second);
        }
    }



    static void addToIndRecordStore(unordered_map<ResourceInfo, vector<IndexRecord*>, ResInfoHash>& indRecordStore,
                                    const vector<Record*>& unIncreWriteRecords)
    {
        for(const Record* rec : unIncreWriteRecords){
            if(rec->opType == ADD){
                addUpdateInfoToRecordStore(indRecordStore, addRecordToIndUpdateInfo(rec));
            }
            else if(rec->opType == MOD){
                addUpdateInfoToRecordStore(indRecordStore, modRecordToIndUpdateInfo(rec));
            }
            else if(rec->opType == DEL){
                addUpdateInfoToRecordStore(indRecordStore, delRecordToIndUpdateInfo(rec));
            }
            else{
                throw string("opType error");
            }
        }
    }



    static void addToDataRecordStore(unordered_map<ResourceInfo, vector<Record*>, ResInfoHash>& dataRecordStore,
                                     const vector<Record*>& unIncreWriteRecords)
    {
        for(const Record* rec : unIncreWriteRecords){                              //数据增量写完成后记录会被释放 所以拷贝（索引增量写还要用）
            dataRecordStore[RecordUtil::recordToResourceInfo(rec)].push_back(new Record(*rec));
        }
    }

    static void redoData(){
        const vector<Record*>& unIncreWriteRecords = Record::readRedoDataRecords();
        if(unIncreWriteRecords.empty()){ return; }

        unordered_map<ResourceInfo, vector<Record*>, ResInfoHash> dataRecordStore;
        addToDataRecordStore(dataRecordStore, unIncreWriteRecords);
        IncreWriteUtil::optimizRecordStore(dataRecordStore);
        IncreWriteUtil::increWriteAccrodUpDateInfo(dataRecordStore);    //在里面dataRecordStore的指针会被释放

        unordered_map<ResourceInfo, vector<uint64_t>, ResInfoHash> bitMapRecordStore;
        addToBitMapRecordStore(bitMapRecordStore, unIncreWriteRecords); //需要依据dataRecordStore 加入
        IncreWriteUtil::increWriteAccrodBitMapUpDateInfo(bitMapRecordStore);

        unordered_map<ResourceInfo, vector<IndexRecord*>, ResInfoHash> indRecordStore;
        addToIndRecordStore(indRecordStore, unIncreWriteRecords);
        IncreWriteUtil::optimizIndexRecordStore(indRecordStore);
        IncreWriteUtil::increWriteAccrodIndexUpDateInfo(indRecordStore, true);//在里面indRecordStore的指针会被释放



        //更新数据同步位置
        IOUtil::updateSyncProgress(Record::getRecordSize() * unIncreWriteRecords.size());

        MemUtil::asyncClearVecMem(unIncreWriteRecords);
    }
};
